package microcredit.model.bo;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.xml.bind.ValidationException;

import microcredit.model.util.ModelUtils;

/**
 * This class handles login and authentication in a safe way using a MD5 hash.
 * Since this is a stateful class it is handled as singleton.
 * 
 * @author Christian Humer
 * @since 1.0
 */
public class BOAuthentication extends BOBase {

	/** The internal md5 hash */
	private static final byte[] MD5HASH = new byte[] { -8, 48, -75, 78, -111,
			-29, -16, 4, -73, 122, -96, -16, -105, 120, -51, 85 };

	private boolean loggedIn;
	private long timeLoggedIn;

	/**
	 * Checks whether the keyword provided was valid.
	 * 
	 * @param keyword
	 *            the keyward as character array. We should not use a String
	 *            because it will otherwise inlinend and be spotted in member.
	 * @return true if valid else false
	 * @throws ValidationException
	 *             - if the keyword was not valid
	 * @throws NoSuchAlgorithmException
	 *             - if the md5 algorithm is not supported on this machine
	 */
	public boolean login(char[] keyword) throws ValidationException,
			NoSuchAlgorithmException {
		MessageDigest digest = MessageDigest.getInstance("MD5");
		byte[] bytes = new byte[keyword.length];
		for (int i = 0; i < keyword.length; i++) {
			char c = keyword[i];
			bytes[i] = (byte) c;
		}
		digest.update(bytes);
		if (!MessageDigest.isEqual(digest.digest(), MD5HASH)) {
			logout();
			throw new ValidationException("Invalid login entered.");
		}
		loggedIn = true;
		timeLoggedIn = ModelUtils.createTimestamp().getTime();
		return true;
	}

	/**
	 * Logs the user current user out.
	 */
	public void logout() {
		loggedIn = false;
		timeLoggedIn = 0;
	}

	/**
	 * Any user action perform on the UI to determine if the login times out.
	 */
	public void userAction() {
		if (loggedIn) {
			timeLoggedIn = ModelUtils.createTimestamp().getTime();
		}
	}

	/**
	 * Checks whether the current login is expired.
	 * 
	 * @return true if expired
	 */
	public boolean isExpired() {
		long newTimestamp = ModelUtils.createTimestamp().getTime();
		return (newTimestamp - timeLoggedIn) > 100000;
	}

	private static BOAuthentication instance;

	/**
	 * Returns the singleton instance of the BO Authentication
	 * 
	 * @return
	 */
	public static BOAuthentication getInstance() {
		if (instance == null) {
			instance = new BOAuthentication();
		}
		return instance;
	}

}
